﻿using System;
using System.Globalization;
using System.Linq;
using ezCloud.Data;
using System.IO;
using System.Threading.Tasks;

namespace ezCloud.Api.Common
{
    public static class NightAudit
    {
        public static void NightAuditScheduler()
        {
            var context = new ezCloudDataContext();
            var allActiveHotels = context.Hotels.Where(hotel => hotel.IsActive).ToList();
            foreach (var hotel in allActiveHotels)
            {
                if ((hotel.LastNightAuditDate == null ||
                     ((DateTime) hotel.LastNightAuditDate).AddMinutes(hotel.TimeZoneOffset) <
                     DateTime.UtcNow.AddMinutes(hotel.TimeZoneOffset).Date) &&
                    hotel.NightAuditTime < DateTime.UtcNow.AddMinutes(hotel.TimeZoneOffset).Subtract(DateTime.Today))
                {
                    //it's time to run Night Audit
                    hotel.LastNightAuditDate = DateTime.UtcNow;
                    context.SubmitChanges();
                    var reservations =
                        context.ReservationRooms.Where(
                            rr => rr.HotelId == hotel.HotelId && rr.BookingStatus == "CHECKIN")
                            .Select(rr => rr.RoomId)
                            .ToList();
                    foreach (var rid in reservations)
                    {
                        var room = context.Rooms.Where(r => r.RoomId == rid).FirstOrDefault();
                        if (room != null)
                        {
                            if (hotel.IsRoomDirtyAfterNighAudit == true)
                            {
                                room.HouseStatus = "DIRTY";
                            }
                            
                        }
                    }
                    var na = new NightAudits();
                    na.HotelId = hotel.HotelId;
                    na.NightAuditTime = DateTime.UtcNow;
                    context.NightAudits.InsertOnSubmit(na);
                    context.SubmitChanges();
                    var noshows =
                        context.ReservationRooms.Where(
                            rr =>
                                rr.HotelId == hotel.HotelId && rr.BookingStatus == "BOOKED" &&
                                rr.ArrivalDate < DateTime.UtcNow).ToList();
                    foreach (var rr in noshows)
                    {
                        var item = new NightAuditItems();
                        item.NightAuditId = na.NightAuditId;
                        item.HotelId = hotel.HotelId;
                        item.ItemType = "NOSHOW";
                        item.ReservationRoomId = rr.ReservationRoomId;
                        context.NightAuditItems.InsertOnSubmit(item);
                    }
                    var overdues =
                        context.ReservationRooms.Where(
                            rr =>
                                rr.HotelId == hotel.HotelId && rr.BookingStatus == "CHECKIN" &&
                                rr.DepartureDate < DateTime.UtcNow).ToList();
                    foreach (var rr in overdues)
                    {
                        var item = new NightAuditItems();
                        item.NightAuditId = na.NightAuditId;
                        item.HotelId = hotel.HotelId;
                        item.ItemType = "OVERDUE";
                        item.ReservationRoomId = rr.ReservationRoomId;
                        context.NightAuditItems.InsertOnSubmit(item);
                    }
                    context.SubmitChanges();
                   // Reports.ExportNightAuditReport(hotel.HotelId, DateTime.Today);
                }
            }
            context.SubmitChanges();
        }

        public static void AutoDeletePOSDraftScheduler()
        {
            using (var context = new ezCloudDataContext())
            {
                var allActiveHotels = context.Hotels.Where(hotel => hotel.IsActive && hotel.POSConfigsList.FirstOrDefault()!=null);
                foreach (var hotel in allActiveHotels)
                {
                    var isPOSModuleActive = hotel.EzHotelModulesList.Where(module => module.EzModules.ModuleCode == "POS" && module.EzModules.Status == true && module.Status == true).ToList().Count > 0;
                    if (isPOSModuleActive &&
                        ((hotel.POSConfigsList.FirstOrDefault().LastRemoveDrafBillDate != null &&
                         ((DateTime)hotel.POSConfigsList.FirstOrDefault().LastRemoveDrafBillDate).AddMinutes(hotel.TimeZoneOffset) >=
                         DateTime.UtcNow.AddMinutes(hotel.TimeZoneOffset).Date)))
                    {
                        continue;
                    }
                    hotel.POSConfigsList.FirstOrDefault().LastRemoveDrafBillDate = DateTime.UtcNow;
                    var allHotelDraftPOS = hotel.DrafPOSPaymentTravellerList;
                    foreach (var draft in allHotelDraftPOS)
                    {
                        if (draft.CreatedDate.Value.AddDays((double)hotel.POSConfigsList.FirstOrDefault().NumberOfDateToRemoveDrafBill).AddMinutes(hotel.TimeZoneOffset) <= DateTime.UtcNow.AddMinutes(hotel.TimeZoneOffset).Date)
                        {
                            context.ExecuteCommand("Delete DrafPOSPaymentTraveller where HotelId={0} and DrafPOSPaymentTravellerId={1}", hotel.HotelId, draft.DrafPOSPaymentTravellerId);
                        }
                    }
                }
                context.SubmitChanges();
            }
        }

        public static void PaymentAuditScheduler()
        {
            var context = new ezCloudDataContext();
            string logAudit = "";
            //test
            var allActiveHotels = context.Hotels.Where(hotel => hotel.IsActive).ToList();
            logAudit += "Start process Payment audit, toltal hotel is processing:" + allActiveHotels.Count().ToString();
            PaymentAuditWriteLog(0, logAudit);
            foreach (var hotel in allActiveHotels)
            {

                if ((hotel.LastPaymentAuditDate != null &&
                     ((DateTime)hotel.LastPaymentAuditDate).AddMinutes(hotel.TimeZoneOffset) >=
                     DateTime.UtcNow.AddMinutes(hotel.TimeZoneOffset).Date) ||
                    new TimeSpan(0, 0, 0) >= DateTime.UtcNow.AddMinutes(hotel.TimeZoneOffset).Subtract(DateTime.Today))
                {
                    PaymentAuditWriteLog(hotel.HotelId, "Not process because time is over");
                    continue;
                }
            
                    
                var ezAccount = context.EzAccounts.FirstOrDefault(acc => acc.HotelId == hotel.HotelId);
                if (ezAccount==null)
                {
                    PaymentAuditWriteLog(hotel.HotelId, "Not process because ezAccount is null");
                    continue;
                }


                logAudit = "Processing....";

                var numberOfHotelDiscount = 0;
                hotel.LastPaymentAuditDate = DateTime.UtcNow;
                var hotelModuleDiscount =
                    context.EzHotelModules.Where(hotelModule => hotelModule.HotelId == hotel.HotelId)
                        .GroupJoin(
                            context.EzHotelDefaultDiscounts.Where(
                                hotelDiscount =>
                                    hotelDiscount.HotelId == hotel.HotelId && 
                                    hotelDiscount.StartDate.Value.Date <= DateTime.UtcNow.Date &&
                                    DateTime.UtcNow.Date <= hotelDiscount.EndDate.Value.Date),
                            hotelModule => hotelModule.EzModules.EzModuleId,
                            hotelDiscount => hotelDiscount.EzDefaultDiscounts.EzModuleId,
                            (hotelModule, hotelDiscount) => new
                            {
                                hotelModule,
                                hotelDiscount,
                                Module = hotelModule.EzModules
                            }).ToList();

                if (hotelModuleDiscount.Count > 0)
                {
                    var totalRooms = hotel.RoomsList.Where(rm => rm.HotelId == hotel.HotelId && rm.IsHidden == false).ToList().Count;
                    var totalAmountPerDay = 0.0M;
                    foreach (var module in hotelModuleDiscount)
                    {

                        if (module.hotelDiscount.Any())
                        {
                            numberOfHotelDiscount = numberOfHotelDiscount + 1;
                            var paymentLogs = new EzPaymentLogs
                            {
                                EzHotelModuleId = module.hotelModule.EzHotelModuleId,
                                HotelId = hotel.HotelId,
                                CreatedDate = DateTime.UtcNow,
                                CreatedUserId = null,
                                LogKey = "DAILY_FEE",
                                Amount = 0.00M,
                                AmountFee = 0.00M,
                                Description = "Phí theo ngày - Module: " + module.Module.ModuleName + " - Tổng: 0 VND"

                                
                            };
                            logAudit += "\n" + "Phí theo ngày - Module: " + module.Module.ModuleName + " - Tổng: 0 VND";

                            context.EzPaymentLogs.InsertOnSubmit(paymentLogs);
                        }
                        else if (ezAccount.Amount + ezAccount.AmountFee > 0)
                        {
                            if (module.hotelModule.Status==false)
                            {
                                var temp =
                                   module.hotelModule.EzHotelModuleLogsList.Where(
                                       log => hotel.LastPaymentAuditDate != null && (log.CreateDate != null &&
                                                                                     log.CreateDate.Value.Date ==
                                                                                     hotel.LastPaymentAuditDate.Value.Date
                                                                                         .AddDays(-1)))
                                       .ToList();

                                if  ( temp.Count==0 || (temp.Count > 0 && temp.All(tmp => tmp.Status != true))) continue;
                            }
                           
                            //if (temp.Count != 0 && (temp.Count <= 0 || temp.All(tmp => tmp.Status != true)))
                            //    continue;
                            
                            var paymentLogs = new EzPaymentLogs
                            {
                                EzHotelModuleId = module.hotelModule.EzHotelModuleId,
                                HotelId = hotel.HotelId,
                                CreatedDate = DateTime.UtcNow,
                                CreatedUserId = null,
                                LogKey = "DAILY_FEE"
                            };



                            var totalModuleAmountRec = module.Module.EzModuleRangerPricesList.Where(range => range.EzModuleId == module.Module.EzModuleId && range.MinRoom <= totalRooms && totalRooms <= range.MaxRoom).Select(p => new { AmountPerDay = p.AmountPerDay }).FirstOrDefault();
                            decimal totalModuleAmount = 0;
                            if (totalModuleAmountRec != null) totalModuleAmount = (decimal)totalModuleAmountRec.AmountPerDay;

                            totalAmountPerDay += totalModuleAmount;
                            var amountTemp = ezAccount.AmountFee - totalModuleAmount;
                            if (amountTemp >= 0)
                            {
                                paymentLogs.AmountFee = module.Module.Amount;
                                paymentLogs.Amount = 0;
                                ezAccount.AmountFee = ezAccount.AmountFee - totalModuleAmount;
                            }
                            else
                            {
                                paymentLogs.AmountFee = ezAccount.AmountFee;
                                paymentLogs.Amount = -amountTemp;
                                ezAccount.AmountFee = 0.00M;
                                ezAccount.Amount = ezAccount.Amount - paymentLogs.Amount;
                            }
                            if (module.Module.Unit == "ROOM")
                            {
                                if (totalRooms!=0)
                                    paymentLogs.Description = "Phí theo ngày - Module: " + module.Module.ModuleName +" - Tổng: " + Convert.ToDecimal(totalModuleAmount / totalRooms).ToString("0,0", CultureInfo.InvariantCulture) + " x " + totalRooms + " = " + Convert.ToDecimal(totalModuleAmount).ToString("0,0", CultureInfo.InvariantCulture) + " VND";
                                else
                                    paymentLogs.Description = "Phí theo ngày - Module: " + module.Module.ModuleName + " - Tổng: " + Convert.ToDecimal(totalModuleAmount).ToString("0,0", CultureInfo.InvariantCulture) + " x " + totalRooms + " = " + Convert.ToDecimal(totalModuleAmount).ToString("0,0", CultureInfo.InvariantCulture) + " VND";
                            }
                            else
                            {
                                paymentLogs.Description = "Phí theo ngày - Module: " + module.Module.ModuleName + " - Tổng: " + Convert.ToDecimal(totalModuleAmount).ToString("0,0", CultureInfo.InvariantCulture) + " VND";
                            }

                            logAudit += "\n" + paymentLogs.Description;

                            context.EzPaymentLogs.InsertOnSubmit(paymentLogs);
                        }
                    }

                    if (totalAmountPerDay > 0)
                    {
                        hotel.RemainingDays = (int)Math.Floor((decimal)(ezAccount.Amount + ezAccount.AmountFee) / totalAmountPerDay);
                        if (hotel.RemainingDays > 0 && hotel.RemainingDays <= 7)
                        //if (hotel.RemainingDays > 0 )
                        {

                            //send notification
                            string notifi = "Xin chào " + hotel.HotelOwnerAspNetUsers.Email + "\n";
                            notifi += "Thời gian sử dụng phần mềm của khách sạn có mã "+ hotel.HotelId.ToString() + " - " + hotel.HotelName.ToString() + " còn " + hotel.RemainingDays.ToString() + " ngày.\n";
                            notifi += "Quý khách lưu ý thanh toán đúng thời hạn để đảm bảo hệ thống hoạt động liên tục.\n";
                            notifi += "Cám ơn quý khách đã tin tưởng và sử dụng dịch vụ của chúng tôi.";
                            Notification.sendNotificationToDevice(hotel.HotelOwnerAspNetUsers.Email, notifi, hotel.HotelId, "ezCloudHotel");

                            notifi = "Hi, " + hotel.HotelOwnerAspNetUsers.Email + " \n";
                            notifi += "Your permission to use the software for hotel "+ hotel.HotelName.ToString() + " (Hotel ID "+ hotel.HotelId.ToString() + ") will expire in "+ hotel.RemainingDays.ToString() + " days.\n";
                            notifi += "Please make prompt payment to ensure uninterrupted access to the system.\n";
                            notifi += "Thank you for using our software!";
                            Notification.sendNotificationToDevice(hotel.HotelOwnerAspNetUsers.Email, notifi, hotel.HotelId, "ezCloudHotel");

                            string subjec = "ezCloudHotel.com - Time to use software hotel / Thông báo thời gian sử dụng phần mềm: " + hotel.HotelName.ToString() + "(Hotel ID: " + hotel.HotelId.ToString() + ")";
                            EmailSender.SendEmailHotelExpiredDateCountDown(hotel.HotelOwnerAspNetUsers.Email, subjec, hotel.HotelOwnerAspNetUsers.Email, hotel.RemainingDays.ToString(),hotel.HotelId,hotel.HotelName);
                            logAudit += "\n Send mail to :"+ hotel.HotelOwnerAspNetUsers.Email+", Remaining day: "+hotel.RemainingDays.ToString() +" was success" ;
                        }
                    }
                }

                if (ezAccount.Amount + ezAccount.AmountFee <= 0)
                {
                    // Check if hotel had any free module
                    if (numberOfHotelDiscount == 0)
                    {
                        var auditLogs = new EzHotelAuditLogs
                        {
                            HotelId = hotel.HotelId,
                            OutOfServiceDate = DateTime.UtcNow
                        };
                        logAudit += "\n Hotel is out of service";
                        context.EzHotelAuditLogs.InsertOnSubmit(auditLogs);
                    }
                }
                PaymentAuditWriteLog(hotel.HotelId, logAudit);
            }
            
            context.SubmitChanges();
            Elastic.IndexLastAudit(context);
        }
        public static async void PaymentAuditWriteLog(int hotelId, string strLog)
        {
            string folderPerDay = System.DateTime.Today.ToString("yyyyMMdd");
            if (!Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + "PaymentLogAudits\\" + folderPerDay + "\\"))
                Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + "PaymentLogAudits\\" + folderPerDay + "\\");
            string logFilePath = AppDomain.CurrentDomain.BaseDirectory + "PaymentLogAudits\\" + folderPerDay + "\\" + hotelId.ToString() + ".log";
            
            StreamWriter log;
            FileStream fileStream = null;
            DirectoryInfo logDirInfo = null;
            FileInfo logFileInfo;

            //string logFilePath = "C:\\Logs\\";
            //logFilePath = logFilePath + "Log-" + System.DateTime.Today.ToString("MM-dd-yyyy") + "." + "txt";
            logFileInfo = new FileInfo(logFilePath);
            logDirInfo = new DirectoryInfo(logFileInfo.DirectoryName);
            //if (!logDirInfo.Exists) logDirInfo.Create();
            if (!logFileInfo.Exists)
            {
                fileStream = logFileInfo.Create();
            }
            else
            {
                fileStream = new FileStream(logFilePath, FileMode.Append);
            }
            log = new StreamWriter(fileStream);
            strLog = "\n"+System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+":" + strLog;
            log.WriteLine(strLog);
            log.Close();
            return;
        }

        public static async void RoomMoveWriteLog(int hotelId, string strLog)
        {
            string folderPerDay = System.DateTime.Today.ToString("yyyyMMdd");
            if (!Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + "RoomMoveLogs\\" + folderPerDay + "\\"))
                Directory.CreateDirectory(AppDomain.CurrentDomain.BaseDirectory + "RoomMoveLogs\\" + folderPerDay + "\\");
            string logFilePath = AppDomain.CurrentDomain.BaseDirectory + "RoomMoveLogs\\" + folderPerDay + "\\" + hotelId.ToString() + ".log";

            StreamWriter log;
            FileStream fileStream = null;
            DirectoryInfo logDirInfo = null;
            FileInfo logFileInfo;

            //string logFilePath = "C:\\Logs\\";
            //logFilePath = logFilePath + "Log-" + System.DateTime.Today.ToString("MM-dd-yyyy") + "." + "txt";
            logFileInfo = new FileInfo(logFilePath);
            logDirInfo = new DirectoryInfo(logFileInfo.DirectoryName);
            //if (!logDirInfo.Exists) logDirInfo.Create();
            if (!logFileInfo.Exists)
            {
                fileStream = logFileInfo.Create();
            }
            else
            {
                fileStream = new FileStream(logFilePath, FileMode.Append);
            }
            log = new StreamWriter(fileStream);
            strLog = "\n" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":" + strLog;
            log.WriteLine(strLog);
            log.Close();
            return;
        }
    }
}